package com.cai310.lottery.web.controller.lottery.jczq;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import net.sf.json.JSONObject;

import com.cai310.lottery.Constant;
import com.cai310.lottery.common.SalesMode;
import com.cai310.lottery.common.SecretType;
import com.cai310.lottery.common.ShareType;
import com.cai310.lottery.common.SubscriptionLicenseType;
import com.cai310.lottery.dto.lottery.jczq.JczqSchemeDTO;
import com.cai310.lottery.entity.user.User;
import com.cai310.lottery.exception.DataException;
import com.cai310.lottery.support.ContentBean;
import com.cai310.lottery.support.UnitsCountUtils;
import com.cai310.lottery.support.jczq.ItemBF;
import com.cai310.lottery.support.jczq.ItemBQQ;
import com.cai310.lottery.support.jczq.ItemJQS;
import com.cai310.lottery.support.jczq.ItemSPF;
import com.cai310.lottery.support.jczq.JczqCompoundContent;
import com.cai310.lottery.support.jczq.JczqContentBean;
import com.cai310.lottery.support.jczq.JczqMatchItem;
import com.cai310.lottery.support.jczq.JczqUtil;
import com.cai310.lottery.support.jczq.PassMode;
import com.cai310.lottery.support.jczq.PassType;
import com.cai310.lottery.support.jczq.PlayType;
import com.cai310.lottery.support.jczq.SchemeType;
import com.cai310.lottery.support.jczq.TicketItem;
import com.cai310.lottery.support.jczq.TicketSplitCallback;
import com.cai310.lottery.web.controller.WebDataException;
import com.cai310.lottery.web.controller.lottery.SchemeCreateForm;
import com.google.common.collect.Lists;

public class JczqSchemeCreateForm extends SchemeCreateForm {
	
	// ------------------------ 复式 -----------------------

	/** 选择的场次内容 */
	private List<JczqMatchItem> items;

	/** 胆码最小命中数 */
	private Integer danMinHit;

	/** 胆码最大命中数 */
	private Integer danMaxHit;

	// --------------------- 单复式共用 --------------------

	/** 方案内容 */
	private String content;
	
	/** 过关方式 */
	private List<PassType> passTypes;

	/** 方案类型 */
	private SchemeType schemeType;
	
	/** 过关类型 */
	private PassMode passMode;

	// ----------------------------------------------------

	@Override
	protected ContentBean buildCompoundContentBean() throws DataException {
		// 在Controller那边做一些数据验证

		Collections.sort(this.items);
		PassType minPassType = passTypes.get(0);// 最小的过关方式

		final List<JczqMatchItem> danList = new ArrayList<JczqMatchItem>();
		final List<JczqMatchItem> unDanList = new ArrayList<JczqMatchItem>();
		for (JczqMatchItem item : items) {
			if (item.isDan())
				danList.add(item);
			else
				unDanList.add(item);
		}

		// 检查设胆数目
		if (danList.size() > minPassType.getMatchCount()) {
			throw new DataException("设置的胆码不能大于最小的过关场次.");
		}

		if (danMinHit == null || danMinHit <= 0)
			danMinHit = danList.size();
		else if (danMinHit > danList.size())
			throw new DataException("模糊设胆不正确.");

		if (danMinHit + unDanList.size() < minPassType.getMatchCount())
			throw new DataException("模糊设胆不正确.");

		if (danMaxHit == null || danMaxHit <= 0)
			danMaxHit = danList.size();

		int units = 0;
		for (PassType passType : this.passTypes) {
			for (final int needs : passType.getPassMatchs()) {
				units += UnitsCountUtils.countUnits(needs, danList, danMinHit, danMaxHit, unDanList);
				if (units > Constant.MAX_UNITS)
					throw new DataException("复式方案单倍注数不能大于" + Constant.MAX_UNITS + "注.");
			}
		}

		JczqCompoundContent content = new JczqCompoundContent();
		content.setItems(items);
		content.setDanMinHit(danMinHit);
		content.setDanMaxHit(danMaxHit);

		return new ContentBean(units, JSONObject.fromObject(content).toString());
	}
	@Override
	protected ContentBean buildSingleContentBean() throws DataException {
		///竞彩添加胜平负单式不同倍数
		throw new RuntimeException("竞彩足球不支持上传.");
	}

	// ================================================================单式
	protected ContentBean buildSingleBetContentBean(JczqContentBean jczqContentBean) throws DataException {
		Map<String, Object> map;
		Integer danMinHit = 0;
		Integer danMaxHit = 0;
		final List<JczqMatchItem> correctList = jczqContentBean.getCorrectList();
		
		PassType minPassType = jczqContentBean.getPassTypes().get(0);// 最小的过关方式

		final List<JczqMatchItem> danList = new ArrayList<JczqMatchItem>();
		final List<JczqMatchItem> unDanList = new ArrayList<JczqMatchItem>();
		for (JczqMatchItem item : correctList) {
			if (item.isDan())
				danList.add(item);
			else
				unDanList.add(item);
		}

		// 检查设胆数目
		if (danList.size() > minPassType.getMatchCount()) {
			throw new DataException("设置的胆码不能大于最小的过关场次.");
		}

		if (danMinHit == null || danMinHit <= 0)
			danMinHit = danList.size();
		else if (danMinHit > danList.size())
			throw new DataException("模糊设胆不正确.");

		if (danMinHit + unDanList.size() < minPassType.getMatchCount())
			throw new DataException("模糊设胆不正确.");

		if (danMaxHit == null || danMaxHit <= 0)
			danMaxHit = danList.size();

		int units = 0;
		for (PassType passType : jczqContentBean.getPassTypes()) {
			for (final int needs : passType.getPassMatchs()) {
				units += UnitsCountUtils.countUnits(needs, danList, danMinHit, danMaxHit, unDanList);
				if (units > Constant.MAX_UNITS)
					throw new DataException("复式方案单倍注数不能大于" + Constant.MAX_UNITS + "注.");
			}
		}

		JczqCompoundContent content = new JczqCompoundContent();
		content.setItems(correctList);
		content.setDanMinHit(danMinHit);
		content.setDanMaxHit(danMaxHit);

		return new ContentBean(units, JSONObject.fromObject(content).toString());
	}
	protected List<JczqContentBean> buildSingleContentBeanList(String schemeContent) throws DataException {
		///竞彩添加胜平负单式不同倍数
		PlayType playType = PlayType.SPF;
		if (StringUtils.isBlank(schemeContent))
			throw new DataException("方案内容为空.");

		String[] arr = schemeContent.split("(\r\n|\n)+");
		///2011301-001*3,1+2011302-001*1$2
		///2011301-001*3,1+2011302-001*1$3 ..场次*投注内容+场次*投注内容$倍数
		List<JczqContentBean> betList = Lists.newArrayList();
		List<JczqMatchItem> correctList;
		String[] betArr;
		String betStr;
		int num = 0;
		Integer multiple = 0;
		JczqContentBean jczqContentBean;
		for (String str : arr) {
			jczqContentBean = new JczqContentBean();
			num++;
			if(str.indexOf("$")==-1)throw new DataException("第["+num+"]注方案倍数错误.");
			betArr = str.split("\\$");
			betStr = betArr[0];
			multiple = Integer.valueOf(betArr[1]);
			if(multiple<1)throw new DataException("第["+num+"]注方案倍数错误.");
			correctList = Lists.newArrayList();
			Map<String, Object> map;
			if(betStr.indexOf("+")==-1)throw new DataException("第["+num+"]注投注内容错误.");
			betArr = betStr.split("\\+");
			String matchKey=null;
			String value=null;
			int units = 1;
			for (String itemStr : betArr) {
				JczqMatchItem item = new JczqMatchItem();
				if(itemStr.indexOf("*")==-1)throw new DataException("第["+num+"]注投注内容错误.");
				matchKey = itemStr.split("\\*")[0];
				value = itemStr.split("\\*")[1];
				item.setMatchKey(matchKey);
				item.setDan(Boolean.FALSE);
				item.setValue(getBetValue(playType,value));
				correctList.add(item);
				units = units*getBetCount(value);
			}
			List<PassType> passTypes = Lists.newArrayList();
			passTypes.add(getPassType(betArr.length,num));
			Collections.sort(correctList);
			jczqContentBean.setCorrectList(correctList);
			jczqContentBean.setMultiple(multiple);
			jczqContentBean.setContent(str);
			jczqContentBean.setSchemeType(SchemeType.SIMPLE_PASS);
			jczqContentBean.setPlayType(playType);
			jczqContentBean.setPassTypes(passTypes);
			jczqContentBean.setUnits(units);
			jczqContentBean.setCost(units*2*multiple);
			betList.add(jczqContentBean);
		}
        return betList;
	}
	public PassType getPassType(Integer betCount,Integer num) throws DataException {
		if(2==betCount){
			return PassType.P2_1;
		}else if(3==betCount){
			return PassType.P3_1;
		}else if(4==betCount){
			return PassType.P4_1;
		}else if(5==betCount){
			return PassType.P5_1;
		}else if(6==betCount){
			return PassType.P6_1;
		}else if(7==betCount){
			return PassType.P7_1;
		}else if(8==betCount){
			return PassType.P8_1;
		}else{
			throw new DataException("第["+num+"]注投注场次错误.");
		}
	}
	public Integer getBetCount(String value) {
		List<String> list = Lists.newArrayList();
		if(value.indexOf(",")!=-1){
			String[] arr = value.split(",");
			for (String str : arr) {
				list.add(str);
			}
		}else{
			list.add(value);
		}
		return list.size();
	}
	public Integer getBetValue(PlayType playType,String value) {
		Integer flag=0;
		List<String> list = Lists.newArrayList();
		if(value.indexOf(",")!=-1){
			String[] arr = value.split(",");
			for (String str : arr) {
				list.add(str);
			}
		}else{
			list.add(value);
		}
		switch (playType) {
		case SPF:
			for (String str : list) {
				flag+=0x1 <<ItemSPF.valueOfValue(str).ordinal();
			}
			return flag;
		case JQS:
			for (String str : list) {
				flag+=0x1 << ItemJQS.valueOfValue(str).ordinal();
			}
			return flag;
		case BF:
			for (String str : list) {
				flag+=0x1 << ItemBF.valueOfValue(str).ordinal();
			}
			return flag;
		case BQQ:
			for (String str : list) {
				flag+=0x1 << ItemBQQ.valueOfValue(str).ordinal();
			}
			return flag;
		default:
			throw new RuntimeException("玩法不正确.");
		}
	}
	
	protected JczqSchemeDTO buildSchemeDTO(JczqContentBean jczqContentBean,User user,Long periodId) throws WebDataException, DataException {
		if (jczqContentBean.getPlayType() == null)
			throw new WebDataException("玩法类型不能为空.");

		if (jczqContentBean.getSchemeType() == null)
			throw new WebDataException("方案类型不能为空.");
		if (jczqContentBean.getPassTypes() == null || jczqContentBean.getPassTypes().isEmpty())
			throw new WebDataException("过关方式不能为空.");
		Integer danMinHit = 0;
		Integer danMaxHit = 0;
		final List<JczqMatchItem> correctList = jczqContentBean.getCorrectList();
			
			
		
		SalesMode salesMode = SalesMode.COMPOUND;
		switch (salesMode) {
		case COMPOUND:
			checkCreateFormOfCOMPOUND(jczqContentBean);
			break;
		case SINGLE:
			throw new WebDataException("目前不支持单式投注.");
		default:
			throw new WebDataException("投注方式不合法.");
		}

		
		JczqSchemeDTO schemeDTO ;
		schemeDTO = new JczqSchemeDTO();;
		if (user == null)
			throw new WebDataException("您还未登录,请登录后再操作.");
		schemeDTO.setSponsorId(user.getId());
		
		if (periodId == null)
			throw new WebDataException("期号对应期Id为空.");
		schemeDTO.setPeriodId(periodId);

		
		schemeDTO.setMode(SalesMode.COMPOUND);


		schemeDTO.setSecretType(SecretType.FULL_SECRET);///接票的都设为保密
		schemeDTO.setSubscriptionLicenseType(SubscriptionLicenseType.PUBLIC_LICENSE);///加入方式都设为公共加入
		
		if (jczqContentBean.getCost() == null || jczqContentBean.getCost() < 2)
			throw new WebDataException("方案金额为空或不合法.");
		schemeDTO.setSchemeCost(jczqContentBean.getCost());

		if (jczqContentBean.getMultiple() == null || jczqContentBean.getMultiple() < 1)
			throw new WebDataException("方案倍数为空或不合法.");
		schemeDTO.setMultiple(jczqContentBean.getMultiple());

		if (jczqContentBean.getUnits() == null || jczqContentBean.getUnits() < 1)
			throw new WebDataException("方案注数为空或不合法.");
		else {
			if (salesMode == SalesMode.SINGLE && jczqContentBean.getUnits() > Constant.MAX_SINGLE_UNITS) {
				throw new WebDataException("单式方案注数不能大于" + Constant.MAX_SINGLE_UNITS + "注.");
			}
			if (salesMode == SalesMode.COMPOUND && jczqContentBean.getUnits() > Constant.MAX_UNITS)
				throw new WebDataException("复式方案注数不能大于" + Constant.MAX_UNITS + "注.");
		}
		schemeDTO.setUnits(jczqContentBean.getUnits());

		int cost = schemeDTO.getUnits() * schemeDTO.getMultiple() * 2;
		if (cost != schemeDTO.getSchemeCost())
			throw new WebDataException("根据注数计算出来的金额与提交的方案金额不一致.");
		
		schemeDTO.setShareType(ShareType.SELF);
		ContentBean contentBean = buildSingleBetContentBean(jczqContentBean);
			if (contentBean == null || StringUtils.isBlank(contentBean.getContent()))
				throw new WebDataException("方案内容为空.");
			else if (!schemeDTO.getUnits().equals(contentBean.getUnits()))
				throw new WebDataException("根据方案内容计算出来的注数与提交的注数不一致.");
		schemeDTO.setContent(contentBean.getContent());
		schemeDTO.setPlayType(jczqContentBean.getPlayType());
		
		schemeDTO.setSchemeType(jczqContentBean.getSchemeType());
		schemeDTO.setPassTypes(jczqContentBean.getPassTypes());

	
		
		final StringBuilder ticketContentBuilder = new StringBuilder();
		TicketSplitCallback callback = new TicketSplitCallback() {

			@Override
			public void handle(List<JczqMatchItem> matchItemList, PassType passType, int multiple) {
				long matchFlag = JczqUtil.chg2flag(matchItemList, correctList);
				TicketItem ticketItem = new TicketItem(matchFlag, passType, multiple);
				ticketContentBuilder.append(ticketItem.toString()).append(TicketItem.ITEM_AND);
			}
		};
		switch (jczqContentBean.getSchemeType()) {
		case SINGLE:
			throw new WebDataException("目前不支持单式投注.");
		case SIMPLE_PASS:
			schemeDTO.setPassMode(PassMode.PASS);
			JczqUtil.splitWithMultiple(callback, jczqContentBean.getMultiple(), jczqContentBean.getPassTypes().get(0),
					correctList);
			break;
		case MULTIPLE_PASS:
			throw new WebDataException("目前不支持组合投注.");
		}
		if (ticketContentBuilder.length() > 0)
			ticketContentBuilder.delete(ticketContentBuilder.length() - TicketItem.ITEM_AND.length(),
					ticketContentBuilder.length());
		schemeDTO.setTicketContent(ticketContentBuilder.toString());
		return schemeDTO;
	}
	protected void checkCreateFormOfCOMPOUND(JczqContentBean jczqContentBean) throws WebDataException {
		final List<JczqMatchItem> correctList = jczqContentBean.getCorrectList();
		if (correctList == null || correctList.isEmpty())
			throw new WebDataException("投注内容不能为空.");

		switch (jczqContentBean.getSchemeType()) {
		case SINGLE:
			throw new WebDataException("过关模式不合法.");
		case SIMPLE_PASS:
			if (correctList.size() > jczqContentBean.getPlayType().getMaxMatchSize())
				throw new WebDataException("[" + jczqContentBean.getPlayType().getText() + "]普通过关选择不能超过" + jczqContentBean.getPlayType().getMaxMatchSize() + "场.");

			if (jczqContentBean.getPassTypes().size() > 1)
				throw new WebDataException("普通过关模式只能选择一个过关方式.");

			PassType passType = jczqContentBean.getPassTypes().get(0);
			if (passType == PassType.P1)
				throw new WebDataException("过关模式不能选择单关过关方式.");
			if (passType.getMatchCount() != correctList.size())
				throw new WebDataException("选择的场次数目与过关方式不匹配.");
			break;
		case MULTIPLE_PASS:
			throw new WebDataException("过关模式不合法.");
		default:
			throw new WebDataException("过关模式不合法.");
		}
	}
	/**
	 * 获取方案内容
	 * 
	 * @return 方案内容
	 * @throws DataException
	 */
	public String getSchemeContent() throws DataException {
		if (isFileUpload())
			return getUploadContent();
		else
			return getContent();
	}
	/**
	 * @return {@link #content}
	 */
	public String getContent() {
		return content;
	}

	/**
	 * @param content the {@link #content} to set
	 */
	public void setContent(String content) {
		this.content = content;
	}
	/**
	 * @return {@link #items}
	 */
	public List<JczqMatchItem> getItems() {
		return items;
	}

	/**
	 * @param items the {@link #items} to set
	 */
	public void setItems(List<JczqMatchItem> items) {
		this.items = items;
	}

	/**
	 * @return {@link #passTypes}
	 */
	public List<PassType> getPassTypes() {
		return passTypes;
	}

	/**
	 * @param passTypes the {@link #passTypes} to set
	 */
	public void setPassTypes(List<PassType> passTypes) {
		this.passTypes = passTypes;
	}

	/**
	 * @return {@link #danMinHit}
	 */
	public Integer getDanMinHit() {
		return danMinHit;
	}

	/**
	 * @param danMinHit the {@link #danMinHit} to set
	 */
	public void setDanMinHit(Integer danMinHit) {
		this.danMinHit = danMinHit;
	}

	/**
	 * @return {@link #danMaxHit}
	 */
	public Integer getDanMaxHit() {
		return danMaxHit;
	}

	/**
	 * @param danMaxHit the {@link #danMaxHit} to set
	 */
	public void setDanMaxHit(Integer danMaxHit) {
		this.danMaxHit = danMaxHit;
	}

	/**
	 * @return the schemeType
	 */
	public SchemeType getSchemeType() {
		return schemeType;
	}

	/**
	 * @param schemeType the schemeType to set
	 */
	public void setSchemeType(SchemeType schemeType) {
		this.schemeType = schemeType;
	}
	public PassMode getPassMode() {
		return passMode;
	}
	public void setPassMode(PassMode passMode) {
		this.passMode = passMode;
	}
	
}
